home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-12-10 | 8.5 KB | 343 lines | [TEXT/KAHL] |
- /*
- ** CTCPAsyncCall.cp
- **
- ** TurboTCP support library
- ** TCP asynchronous call class
- **
- ** Copyright © 1993, FrostByte Design / Eric Scouten
- **
- */
-
-
- #include "CTCPAsyncCall.h"
-
- #include "CTCPDriver.h"
- #include "CTCPStream.h"
-
-
- // —— initiate TCP calls ——
-
- /*______________________________________________________________________
- **
- ** ITCPAsyncCall
- **
- ** Create a new TCP asynchronous call object. This object scheme, albeit complex, allows
- ** calls to be truly asynchronous. Control is returned immediately to the caller, which goes
- ** about other business until completion has occurred.
- **
- ** theStream (CTCPStream *): the stream which requested the call
- **
- */
-
- void CTCPAsyncCall::ITCPAsyncCall (CTCPStream *theStream)
-
- {
- itsStream = theStream;
- qEntry.qSelfLink = this;
- bypassTarget = NULL;
- bypassProc = NULL;
- MoveHHi((Handle) this); // since we pass a pointer to the call block,
- this->Lock(TRUE); // the object can’t move
- }
-
-
- /*______________________________________________________________________
- **
- ** DoAsyncCall
- **
- ** Fills in the standard parameters for a TCP Device Manager call and executes the call.
- **
- ** theCsCode (short): TCP operation code
- ** theParamBlockPtr (TCPiopb *): parameter block for TCP call
- **
- ** return (OSErr): result code
- **
- */
-
- OSErr CTCPAsyncCall::DoAsyncCall (short theCsCode, TCPiopb *theParamBlockPtr)
-
- {
- BlockMove(theParamBlockPtr, &itsParamBlock, sizeof (TCPiopb));
- itsParamBlock.ioCompletion = (TCPIOCompletionProc) &CompletionProc;
- itsParamBlock.ioCRefNum = gTCPDriver->GetTCPRefNum();
- itsParamBlock.csCode = theCsCode;
- PBControlAsync((ParmBlkPtr) &itsParamBlock);
- return (itsParamBlock.ioResult);
- }
-
-
- // —— process TCP call completion ——
-
- /*______________________________________________________________________
- **
- ** ProcessCompletion
- **
- ** Respond to completion of this TCP call and all calls following it in the completion loop.
- ** After running through this loop, disposes of the call object, UNLESS it was a successful
- ** auto-receive call.
- **
- */
-
- void CTCPAsyncCall::ProcessCompletion (void)
-
- {
- Boolean disposeWhenDone;
-
-
- // dispatch to general completion routine or to optimized routine for no-copy-receive calls
-
- TRY {
- if (itsParamBlock.csCode == TCPNoCopyRcv)
- disposeWhenDone = DispatchNoCopyRcv();
- else
- disposeWhenDone = Dispatch();
- if (disposeWhenDone) {
- itsStream->ProcessAsyncCompletion(this);
- Dispose();
- }
- } CATCH {
- itsStream->ProcessAsyncCompletion(this);
- Dispose();
- } ENDTRY;
-
- }
-
-
- /*______________________________________________________________________
- **
- ** Dispatch (protected method)
- **
- ** Called by ProcessCompletion to report back to the CTCPStream object. Does not dispose
- ** of object. Also, does not handle TCPNoCopyRcv commands (see DispatchNoCopyRcv
- ** method below).
- **
- ** return (Boolean): TRUE to dispose of call object when done
- **
- */
-
- Boolean CTCPAsyncCall::Dispatch (void)
-
- {
- rdsEntry *RDSPtr;
- wdsEntry *WDSPtr;
-
- if (itsParamBlock.ioResult) {
-
- // command failed, what was it?
-
- switch (itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream->HandleOpenFailed(itsParamBlock.ioResult);
- break;
-
- case TCPSend:
- itsStream->HandleSendFailed((wdsEntry *) itsParamBlock.csParam.send.wdsPtr,
- itsParamBlock.ioResult);
- break;
-
- case TCPRcv:
- if (itsParamBlock.ioResult == connectionClosing)
- break;
-
- case TCPClose:
- if (itsParamBlock.ioResult == connectionDoesntExist)
- break;
-
- default:
- itsStream->HandleTCPError(itsParamBlock.ioResult, itsParamBlock.csCode);
- break;
-
- }
- }
- else {
-
- // no error, dispatch success — what type of call was this anyway?
-
- switch (itsParamBlock.csCode) {
-
- case TCPPassiveOpen:
- case TCPActiveOpen:
- itsStream->HandleOpened();
- break;
-
- case TCPSend:
- WDSPtr = (wdsEntry *) itsParamBlock.csParam.send.wdsPtr;
- itsStream->HandleDataSent(WDSPtr);
- if (itsParamBlock.csParam.open.security) {
- while ((*WDSPtr).length) {
- ForgetPtr((*WDSPtr).ptr);
- WDSPtr++;
- }
- }
- ForgetPtr(itsParamBlock.csParam.send.wdsPtr);
- break;
-
- case TCPRcv:
- if (itsParamBlock.csParam.receive.urgentFlag)
- itsStream->RcvUrgentBegin();
- if (itsParamBlock.csParam.receive.markFlag)
- itsStream->RcvUrgentMark();
- itsStream->HandleDataArrived(itsParamBlock.csParam.receive.rcvBuff,
- itsParamBlock.csParam.receive.rcvBuffLen,
- itsStream->RcvUrgentStatus());
- break;
-
- case TCPClose:
- itsStream->HandleClosed();
- break;
-
- case TCPRcvBfrReturn:
-
- // if auto-receiving, re-issue the TCPNoCopyRcv command with same paramters
-
- if ((itsParamBlock.csParam.open.options[36]) && (itsStream->hasSessionOpen)) {
- itsParamBlock.csParam.receive.rdsLength = itsParamBlock.csParam.open.options[36];
- itsParamBlock.ioCompletion = (TCPIOCompletionProc) &CompletionProc;
- itsParamBlock.csCode = TCPNoCopyRcv;
- PBControlAsync((ParmBlkPtr) &itsParamBlock);
- return (FALSE); // make sure call object stays around
- }
- else
- ForgetPtr(itsParamBlock.csParam.receive.rdsPtr);
- break;
-
- } // switch
- } // if…else
-
- return (TRUE); // always dispose of call object when done
-
- }
-
-
- /*______________________________________________________________________
- **
- ** DispatchNoCopyRcv (protected method)
- **
- ** Optimized routine to handle completion of TCPNoCopyRcv calls.
- **
- ** return (Boolean): TRUE to dispose of call object when done
- **
- */
-
- Boolean CTCPAsyncCall::DispatchNoCopyRcv (void)
-
- {
- rdsEntry *RDSPtr;
-
-
- // respond to error condition
-
- if (itsParamBlock.ioResult) {
- if ((itsParamBlock.ioResult != connectionClosing) && (itsParamBlock.ioResult != connectionDoesntExist))
- itsStream->HandleTCPError(itsParamBlock.ioResult, itsParamBlock.csCode);
- ForgetPtr(itsParamBlock.csParam.receive.rdsPtr);
- return (TRUE); // always dispose when call fails
- }
-
-
- // update urgent flags
-
- if (itsParamBlock.csParam.receive.urgentFlag)
- itsStream->RcvUrgentBegin();
- if (itsParamBlock.csParam.receive.markFlag)
- itsStream->RcvUrgentMark();
-
-
- // run through RDS and process each block of data
-
- RDSPtr = (rdsEntry *) itsParamBlock.csParam.receive.rdsPtr;
-
- while ((*RDSPtr).length) {
- if (bypassProc)
- (bypassProc) (bypassTarget, (*RDSPtr).ptr, (*RDSPtr).length, itsStream->rcvUrgent);
- else
- itsStream->HandleDataArrived((*RDSPtr).ptr,
- (*RDSPtr).length, itsStream->rcvUrgent);
- RDSPtr++;
- }
-
-
- // return the buffers to MacTCP
-
- itsParamBlock.csCode = TCPRcvBfrReturn;
- PBControlAsync((ParmBlkPtr) &itsParamBlock);
-
-
- // if auto-receiving, the call will be reissued when the BfrReturn call is completed
-
- return (FALSE); // keep call object around
-
- }
-
-
- // —— bypass procedure linkage ——
-
- /*______________________________________________________________________
- **
- ** SetRcvBypassProc
- **
- ** Install a receive bypass procedure.
- **
- ** aRcvBypassTarget (CObject *): the object to pass to the bypass procedure
- ** aRcvBypassProc (RcvBypassProc): the receive bypass procedure
- **
- */
-
- void CTCPAsyncCall::SetRcvBypassProc (CObject *aRcvBypassTarget,
- RcvBypassProc aRcvBypassProc)
-
- {
- bypassTarget = aRcvBypassTarget;
- bypassProc = aRcvBypassProc;
- }
-
-
- /***********************************************************************
- ************************************************************************
- **
- ** INTERRUPT-LEVEL routine follows. This routine cannot make memory allocations, cannot make
- ** synchronous TCP calls, and cannot use the Think C profiler.
- **
- */
-
- #pragma options(!force_frame, !profile)
-
-
- // inline assembly code used by CompletionProc
-
- #pragma parameter __A0 GetTheCall ()
- CTCPAsyncCall *GetTheCall (void) = {0x5988, 0x2050}; // SUBQ.L #4,A0
- // // MOVE.L (A0),A0
- // remember that theCall->qEntry.qSelfLink is immediately before itsParamBlock
-
-
- // —— completion procedure ——
-
- /*______________________________________________________________________
- **
- ** CompletionProc (private static method)
- **
- ** The asynchronous completion routine. Recieves notification that any asynchronous
- ** TCP I/O operation has been completed. This routine is used for all TCP calls placed by
- ** CTCPAsyncCall::DoAsyncCall.
- **
- ** Send notification to the TCP driver object that this call has been completed. The driver
- ** then queues the call for processing at the next event loop.
- **
- ** register A0 (struct TCPiobp *): the TCP I/O parameter block
- **
- */
-
- pascal void CTCPAsyncCall::CompletionProc (void)
-
- {
- register CTCPAsyncCall *theCall = GetTheCall();
-
- theCall->qEntry.qType = asyncCall;
- Enqueue((QElemPtr) &(theCall->qEntry), &(gTCPDriver->asyncQueue));
- // CTCPDriver::ProcessNetEvents will pick this up later
-
- }
-